﻿using System;
using System.IO;
using System.Windows.Input;

namespace SampleCode.VirtualFS.ViewModel
{
    /// <summary>
    /// A file View Model
    /// </summary>
    public class FsFileViewModel : FsViewModelBase
    {
        private FsFileInfo _fileInfo;
        private readonly FsDisk _disk;
        private FsFileStream _stream;

        /// <summary>
        /// A ctor
        /// </summary>
        /// <param name="disk"></param>
        /// <param name="fileInfo"></param>
        public FsFileViewModel(FsDisk disk, FsFileInfo fileInfo) : this(disk, fileInfo, false)
        {
        }

        /// <summary>
        /// A ctor, which is used, when a file is created - it turns on edit mode
        /// </summary>
        /// <param name="disk"></param>
        /// <param name="fileInfo"></param>
        /// <param name="inEditMode"></param>
        public FsFileViewModel(FsDisk disk, FsFileInfo fileInfo, bool inEditMode) : this(disk, fileInfo, inEditMode, false)
        {
        }

        /// <summary>
        /// A ctor, which is used, when displaying search results - it turns on displaying full path as name
        /// </summary>
        /// <param name="disk"></param>
        /// <param name="fileInfo"></param>
        /// <param name="inEditMode"></param>
        /// <param name="isSearchResult"></param>
        public FsFileViewModel(FsDisk disk, FsFileInfo fileInfo, bool inEditMode, bool isSearchResult)
        {
            IsReadOnly = isSearchResult;
            InEditMode = inEditMode;

            _disk = disk;
            _fileInfo = fileInfo;

            _disk.FileChanged += OnFileChanged;
        }

        // displayed properties

        public override string Name
        {
            get
            {
                // If this entity is read-only - it is displayed in the list of search results.
                // In this case returning the full path as file name
                if (IsReadOnly)
                    return FullName;

                return _fileInfo.Name;
            }
            set
            {
                if (IsReadOnly)
                    return;

                string parentFile = _fileInfo.FullName.Substring(0, _fileInfo.FullName.Length - _fileInfo.Name.Length);
                _disk.RenameFile(_fileInfo.FullName, parentFile + value);
            }
        }

        public string FullName { get { return _fileInfo.FullName; } }

        public int Length
        {
            get { return _fileInfo.Length; }
        }

        public DateTime TimeCreated
        {
            get { return _fileInfo.TimeCreated; }
        }

        public DateTime TimeModified
        {
            get { return _fileInfo.TimeModified; }
        }

        public string Text
        {
            get; set;
        }

        private FsRelayCommand _removeFileCommand;
        /// <summary>
        /// Remove file command
        /// </summary>
        public ICommand RemoveFileCommand
        {
            get
            {
                return _removeFileCommand ?? (_removeFileCommand = new FsRelayCommand
                (
                    _ => _disk.RemoveFile(FullName)
                ));
            }
        }

        private FsRelayCommand _openFileCommand;
        /// <summary>
        /// Open file for editing command
        /// </summary>
        public ICommand OpenFileCommand
        {
            get
            {
                return _openFileCommand ?? (_openFileCommand = new FsRelayCommand( _ => OpenFile() ));
            }
        }

        private FsRelayCommand _closeFileCommand;
        /// <summary>
        /// Close file command
        /// </summary>
        public ICommand CloseFileCommand
        {
            get
            {
                return _closeFileCommand ?? (_closeFileCommand = new FsRelayCommand( _ => CloseFile() ));
            }
        }

        /// <summary>
        /// Opens the file for editing
        /// </summary>
        private void OpenFile()
        {
            using (var rs = _disk.OpenFile(FullName, false))
            {
                using (var sr = new StreamReader(rs))
                {
                    Text = sr.ReadToEnd();
                }
            }

            _stream = _disk.OpenFile(FullName, true);

            OnPropertyChanged("Text");
        }

        /// <summary>
        /// Closes file and saves changes
        /// </summary>
        private void CloseFile()
        {
            _stream.SetLength(0);
            using (var sw = new StreamWriter(_stream))
            {
                sw.Write(Text);
            }

            _stream.Dispose();
            _stream = null;
        }

        /// <summary>
        /// File changed event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnFileChanged(object sender, FsFileChangedEventArgs e)
        {
            if (!_fileInfo.IsTheSameFile(e.FileInfo))
                return;

            _fileInfo = e.FileInfo;

            OnPropertyChanged("Name");
            OnPropertyChanged("FullName");
            OnPropertyChanged("Length");
            OnPropertyChanged("TimeCreated");
            OnPropertyChanged("TimeModified");
        }

        protected override void OnDispose()
        {
            _disk.FileChanged -= OnFileChanged;

            if(_stream != null)
                _stream.Dispose();
            _stream = null;
        }
    }
}
